//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "cmodule.h"
#include "cprocess.h"
#include <aura.h>

#define START_LOCK(hLock) do {AuraCriticalSection_Enter(hLock); }while(0)
#define END_LOCK(hLock)   do {AuraCriticalSection_Enter(hLock); }while(0)

CModule::~CModule()
{
    if (NULL != m_hModule) {
        AuraModule_Unload(m_hModule);
        m_hModule = NULL;
    }
}

ECode CModule::Initialize(
    /* [in] */ Aura_Handle hModule)
{
    ECode ec = NOERROR;

    assert(NULL != hModule);

    m_hModule = hModule;
    ec = AuraModule_GetInformation(m_processId,
                       hModule,
                      (Aura_Address *)&m_baseAddr,
                      (Aura_Address *)&m_entryPoint,
                      (Aura_MemorySize *)&m_sizeofImage);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = AuraModule_GetFileName(m_hModule, m_name, m_path);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    return NOERROR;

ErrorExit:
    return ec;
}

ECode CModule::Initialize(
    /* [in] */ WString name,
    /* [in] */ ModuleLoadFlags flags)
{
    ECode ec = NOERROR;

    assert(!name.IsNullOrEmpty());

    ec = AuraModule_Load((Aura_PWChar)(const wchar_t *)name,
                      flags,
                      &m_hModule);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = AuraModule_GetInformation(m_processId,
                       m_hModule,
                      (Aura_Address *)&m_baseAddr,
                      (Aura_Address *)&m_entryPoint,
                      (Aura_MemorySize *)&m_sizeofImage);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = AuraModule_GetFileName(m_hModule, m_name, m_path);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    return NOERROR;

ErrorExit:
    if (NULL != m_hModule) {
        AuraModule_Unload(m_hModule);
        m_hModule = NULL;
    }
    return ec;
}

UInt32 CModule::AddRef()
{
    Int32 nRefs = m_cRef.Increment();

    return (UInt32)nRefs;
}

UInt32 CModule::Release()
{
    Int32 nRefs = m_cRef.Decrement();

    if (0 == nRefs) {
        ((CProcess *)m_pOwner)->DetachModule(this);
        delete this;
    }
    return (UInt32)nRefs;
}

ECode CModule::Aggregate(AggrType type, IInterface*pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CModule::GetDomain(IInterface** ppObj)
{
    return E_NOT_IMPLEMENTED;
}

PInterface CModule::Probe(REIID riid)
{
    if (riid == EIID_IInterface) {
        return (IInterface *)(IModule *)this;
    }
    else if (riid == EIID_IModule) {
        return (IModule *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CModule;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface) &EIID_IModule;
    }

    return NULL;
}

ECode CModule::GetBaseAddress(
    /* [out] */ Address * pBase)
{
    if (NULL == pBase) {
        return E_INVALID_ARGUMENT;
    }

    *pBase = m_baseAddr;

    return NOERROR;
}

ECode CModule::GetEntryPointAddress(
    /* [out] */ Address * pEntryPoint)
{
    if (NULL == pEntryPoint) {
        return E_INVALID_ARGUMENT;
    }

    *pEntryPoint = m_entryPoint;

    return NOERROR;
}

ECode CModule::GetMemorySize(
    /* [out] */ MemorySize * pSize)
{
    if (NULL == pSize) {
        return E_INVALID_ARGUMENT;
    }

    *pSize = m_sizeofImage;

    return NOERROR;
}

ECode CModule::GetName(
    /* [out] */ WStringBuf * pName)
{
    if ((NULL == pName) || !pName->GetCapacity()) {
        return E_INVALID_ARGUMENT;
    }

    pName->Copy(m_name);

    return NOERROR;
}

ECode CModule::GetFullPath(
    /* [out] */ WStringBuf * pName)
{
    if ((NULL == pName) || !pName->GetCapacity()) {
        return E_INVALID_ARGUMENT;
    }
    pName->Copy(m_path);

    return NOERROR;
}

ECode CModule::GetProcAddressByName(
    /* [in]  */ AString name,
    /* [out] */ Address * pAddress)
{
    if (name.IsNullOrEmpty() || (NULL == pAddress)) {
        return E_INVALID_ARGUMENT;
    }

    return AuraModule_GetProcAddressByName(m_hModule,
                        (Aura_PChar)(const char *)name,
                        (Aura_Address *)pAddress);
}

ECode CModule::GetProcAddressByOrdinal(
    /* [in]  */ Int32 ordinal,
    /* [out] */ Address * pAddress)
{
    if ((ordinal < 0) || (NULL == pAddress)) {
        return E_INVALID_ARGUMENT;
    }

    return AuraModule_GetProcAddressByOrdinal(m_hModule,
                         ordinal,
                        (Aura_Address *)pAddress);
}

ECode CModule::GetResourceSection(
    /* [out] */ Address * pAddress)
{
    if (NULL == pAddress) {
        return E_INVALID_ARGUMENT;
    }

    return AuraModule_GetResourceSection(m_baseAddr,
                         (Aura_Address *)pAddress);
}

ECode CModule::GetSectionByName(
    /* [in]  */ AString Name,
    /* [out] */ Address * pAddress)
{
    if (Name.IsNullOrEmpty()
        || (NULL == pAddress)) {
        return E_INVALID_ARGUMENT;
    }
    //TODO: just to meet the need for caller.
    *pAddress = 0;
    return NOERROR;
}

ECode CModule::FindResource(
    /* [in]  */ WString name,
    /* [in]  */ WString type,
    /* [out] */ Address * pAddress,
    /* [out] */ MemorySize * pSize)
{
    if (name.IsNullOrEmpty()
        || type.IsNullOrEmpty()
        || (NULL == pAddress)
        || (NULL == pSize)) {
        return E_INVALID_ARGUMENT;
    }

    return AuraModule_GetResource(m_hModule,
                       (Aura_PWChar)(const wchar_t *)name,
                       (Aura_PWChar)(const wchar_t *)type,
                       (Aura_Address *)pAddress,
                       (Aura_MemorySize *)pSize);
}

